package org.mengyun.tcctransaction.utils;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.mengyun.tcctransaction.Compensable;
import org.mengyun.tcctransaction.api.ConsumerTransactionContextExtInfo;
import org.mengyun.tcctransaction.api.ReadonlyTransactionContext;
import org.mengyun.tcctransaction.common.MethodType;
import org.mengyun.tcctransaction.api.TransactionContext;

import java.lang.reflect.Method;

/**
 * Created by changmingxie on 11/21/15.
 */
public class CompensableMethodUtils {

    public static MethodType calculateMethodType( TransactionContext transactionContext, boolean isCompensable) {
        boolean isValidTransactionContext = transactionContext != null
                && !(transactionContext instanceof ReadonlyTransactionContext)
                && !(transactionContext instanceof ConsumerTransactionContextExtInfo);

        if (!isValidTransactionContext && isCompensable) {
            //isRootTransactionMethod
            return MethodType.ROOT;
        } else if (!isValidTransactionContext && !isCompensable) {
            //isSoaConsumer
            return MethodType.CONSUMER;
        } else if (isValidTransactionContext && isCompensable) {
            //isSoaProvider
            return MethodType.PROVIDER;
        } else {
            return MethodType.NORMAL;
        }
    }

    public static int getTransactionContextParamPosition(Class<?>[] parameterTypes) {
        int i;
        for (i = 0; i < parameterTypes.length; i++) {
            if (parameterTypes[i].equals(org.mengyun.tcctransaction.api.TransactionContext.class)) {
                break;
            }
        }
        return i;
    }

    public static TransactionContext getTransactionContextFromArgs(Object[] args) {
        TransactionContext transactionContext = null;

        for (Object arg : args) {
            if (arg != null && org.mengyun.tcctransaction.api.TransactionContext.class.isAssignableFrom(arg.getClass())) {
                transactionContext = (org.mengyun.tcctransaction.api.TransactionContext) arg;
            }
        }

        return transactionContext;
    }


    public static Compensable getCompensable(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();

        Compensable compensable = method.getAnnotation(Compensable.class);

        if (compensable == null) {
            Method targetMethod;
            try {
                targetMethod = pjp.getTarget().getClass().getMethod(method.getName(), method.getParameterTypes());

                if (targetMethod != null) {
                    compensable = targetMethod.getAnnotation(Compensable.class);
                }

            } catch (NoSuchMethodException e) {
                compensable = null;
            }

        }
        return compensable;
    }
}
